<!DOCTYPE html>
<html>

<head>
  <meta http-equiv="content-type" content="text/html; charset=UTF-8">
  <title>Viz Pos</title>

  <script src="https://cdn.plot.ly/plotly-latest.min.js"></script>

  <style id="compiled-css" type="text/css">
    #dropzone {
      background-color: #F8F0D7;
      border: solid 3px #ffcc88;
      min-height: 50px;
      padding: 20px;
      text-shadow: 1px 1px 0 #fff;
    }

    .setzone {
      background-color: #F8F8F0;
      border: solid 1px #e6e6e6;
      padding: 10px;
      margin-top: 10px;
    }

    #dropzone.dropover {
      background-color: #cff;
    }

    .btn {
      padding: 7px 10px 7px 10px;
      font-size: 12px;
      font-weight: bold;
      letter-spacing: 1px;
      border: 1px solid #CCC;
      border-bottom-color: #C6C6C6;
      border-radius: 3px;
    }
  </style>

  <script type="text/javascript">

    var myViz = {};
    myViz.posDict = {};     // データ保持
    myViz.playflag = false; // 再生中か

    window.onload = function () {
      // Drag and Dropの設定
      var elDrop = document.getElementById('dropzone');
      var elFiles = document.getElementById('files');

      elDrop.addEventListener('dragover', function (event) {
        event.preventDefault();
        event.dataTransfer.dropEffect = 'copy';
        showDropping();
      });

      elDrop.addEventListener('dragleave', function (event) {
        hideDropping();
      });

      elDrop.addEventListener('drop', function (event) {
        event.preventDefault();
        hideDropping();

        var files = event.dataTransfer.files;
        showFiles(files);
      });

      function showDropping() {
        elDrop.classList.add('dropover');
      }

      function hideDropping() {
        elDrop.classList.remove('dropover');
      }

      // ドロップ時に呼ばれる関数
      function showFiles(files) {
        if (files.length < 1) {
          alert("drop no file");
        }

        myViz.posDict = {};
        var el_fr_min = document.getElementById('fr_min');
        var el_fr_max = document.getElementById('fr_max');
        var el_fr = document.getElementById('fr');
        el_fr_min.value = '';
        el_fr_max.value = '';

        for (var i = 0; i < files.length; i++) {

          //FileReaderの作成
          var reader = new FileReader();
          //テキスト形式で読み込む
          reader.readAsText(files[i]);

          console.log(files[i].name);

          //読込終了後の処理
          reader.onload = function (ev) {
            var max_x = -99999, max_y = -99999, max_z = -99999, min_x = 99999, min_y = 99999, min_z = 99999;
            var jsonData = JSON.parse(ev.target.result)["frames"];
            var max_fno = 0;
            var min_fno = -1;

            Object.keys(jsonData).forEach(function (fno) {
              if (min_fno < 0) {
                min_fno = fno;
                console.log("min_fno: " + min_fno);
              }
              console.log("fno: " + fno);
              console.log("jsonData[fno]: " + jsonData[fno]);
              var bf_json = jsonData[fno]["mediapipe"];
              console.log("bf_json: " + bf_json);
              if (bf_json === undefined) {
                return;
              }
              var bf_list = [];
              max_fno = fno;
              Object.keys(bf_json).forEach(function (bone_name) {
                var bf = bf_json[bone_name];
                bf.fno = parseInt(fno);
                bf.name = bone_name;
                var x = parseFloat(bf.x) * 100;
                var y = parseFloat(bf.y) * 100;
                var z = parseFloat(bf.z) * 100;
                bf.x = x;
                bf.y = z;
                bf.z = y;
                bf_list.push(bf);

                if (bf.x > max_x) { max_x = bf.x };
                if (bf.x < min_x) { min_x = bf.x };
                if (bf.y > max_y) { max_y = bf.y };
                if (bf.y < min_y) { min_y = bf.y };
                if (bf.z > max_z) { max_z = bf.z };
                if (bf.z < min_z) { min_z = bf.z };
              });
              myViz.posDict['3d' + fno] = bf_list;
            });

            document.getElementById("x_min").value = Math.floor(min_x / 100) * 100;
            document.getElementById("x_max").value = Math.ceil(max_x / 100) * 100;
            document.getElementById("y_min").value = Math.floor(min_y / 100) * 100;
            document.getElementById("y_max").value = Math.ceil(max_y / 100) * 100;
            document.getElementById("z_min").value = Math.floor(min_z / 100) * 100;
            document.getElementById("z_max").value = Math.ceil(max_z / 100) * 100;

            // 行数をFrameに表示
            document.getElementById('fr_min').value = min_fno;
            document.getElementById('fr_max').value = max_fno;

            // Frameを0にする
            document.getElementById('fr').value = min_fno;

            plotpose();
          }
        }
      }
    }

    function frameMove(val) {
      var val_new = parseInt(document.getElementById('fr').value) + val;
      var val_max = parseInt(document.getElementById('fr_max').value);
      var val_min = parseInt(document.getElementById('fr_min').value);

      if (isNaN(val_max)) {
        return;
      }
      if (val_new > val_max) {
        val_new = val_max;
      } else if (val_new < val_min) {
        val_new = val_min;
      }

      document.getElementById('fr').value = val_new;
      plotpose();
    }

    function next() {
      var start = Date.now();
      var val_new = parseInt(document.getElementById('fr').value) + 1;
      var val_max = parseInt(document.getElementById('fr_max').value);
      var val_min = parseInt(document.getElementById('fr_min').value);
      var interval = parseFloat(document.getElementById('interval').value);

      if (isNaN(val_max)) {
        return;
      }
      if (val_new > val_max) {
        document.getElementById('fr').value = val_min;
        return;
      }
      document.getElementById('fr').value = val_new;
      plotpose();
      var end = Date.now();
      // フレーム間のインターバルを設定
      if (end - start > interval) {
        interval = 0;
      } else {
        interval = interval + start - end;
      }
      if (myViz.playflag == true) {
        setTimeout(function () { next() }, interval);    // 
      }
    }

    function start() {
      myViz.playflag = true;
      setTimeout(function () { next() }, 0);
    }

    function stop() {
      myViz.playflag = false;
    }

    function plotpose() {
      var line_no = document.getElementById('fr').value
      var poslist = myViz.posDict['3d' + line_no];

      if (poslist === undefined) {
        return
      }

      var bone_names = {};
      var xpos = {};
      var ypos = {};
      var zpos = {};
      var key = 0;
      for (var i = 0; i < poslist.length; i++) {
        key = poslist[i].name;
        xpos[key] = poslist[i].x;
        ypos[key] = poslist[i].y;
        zpos[key] = poslist[i].z;
        bone_names[key] = poslist[i].name
      }

      var order = [['left shoulder', 'right shoulder'],
      ['left hip', 'right hip'],
      ['left shoulder', 'left elbow', 'left wrist', 'left index'],
      ['right shoulder', 'right elbow', 'right wrist', 'right index'],
      ['left hip', 'left knee', 'left ankle'],
      ['right hip', 'right knee', 'right ankle'],
      ['left wrist', 'left thumb'],
      ['right wrist', 'right thumb'],
      ['left wrist', 'left pinky'],
      ['right wrist', 'right pinky'],
      ];
      var x = [];
      var y = [];
      var z = [];
      var text = [];

      for (var i = 0; i < order.length; i++) {
        x.push([]);
        y.push([]);
        z.push([]);
        text.push([]);
        for (var j = 0; j < order[i].length; j++) {
          x[i].push(xpos[order[i][j]]);
          y[i].push(ypos[order[i][j]]);
          z[i].push(zpos[order[i][j]]);
          text[i].push(order[i][j]);
        }
      }

      var x_min = parseFloat(document.getElementById("x_min").value);
      var x_max = parseFloat(document.getElementById("x_max").value);
      var y_min = parseFloat(document.getElementById("y_min").value);
      var y_max = parseFloat(document.getElementById("y_max").value);
      var z_min = parseFloat(document.getElementById("z_min").value);
      var z_max = parseFloat(document.getElementById("z_max").value);
      var distance = parseFloat(document.getElementById("distance").value);
      var elev = parseFloat(document.getElementById("elev").value);
      var azim = parseFloat(document.getElementById("azim").value);

      // camera
      var camera_x = 0;
      var camera_y = -1 * distance;
      var camera_z = 0;
      // x rotation
      var camera_tmp1_x = camera_x;
      var camera_tmp1_y = Math.cos(-1 * elev / 180 * Math.PI) * camera_y - Math.sin(-1 * elev / 180 * Math.PI) * camera_z;
      var camera_tmp1_z = Math.sin(-1 * elev / 180 * Math.PI) * camera_y + Math.cos(-1 * elev / 180 * Math.PI) * camera_z;
      // z rotation
      var camera_x = Math.cos(azim / 180 * Math.PI) * camera_tmp1_x - Math.sin(azim / 180 * Math.PI) * camera_tmp1_y;
      var camera_y = Math.sin(azim / 180 * Math.PI) * camera_tmp1_x + Math.cos(azim / 180 * Math.PI) * camera_tmp1_y;
      var camera_z = camera_tmp1_z;

      var plot_title = 'Frame ' + line_no;

      Plotly.react('graph',
        [
          {
            type: 'scatter3d',
            mode: 'lines+markers',
            x: x[0],
            y: y[0],
            z: z[0],
            text: text[0],
            name: 'center',
            opacity: 1,
            line: {
              width: 6,
              color: 'rgb(46, 204, 113)',
              reversescale: false
            },
            marker: {
              color: 'rgb(46, 204, 113)',
              size: 2
            }
          },
          {
            type: 'scatter3d',
            mode: 'lines+markers',
            x: x[1],
            y: y[1],
            z: z[1],
            text: text[1],
            name: 'left',
            opacity: 2,
            line: {
              width: 6,
              color: 'rgb(46, 204, 113)',
              reversescale: false
            },
            marker: {
              color: 'rgb(46, 204, 113)',
              size: 2
            }
          },
          {
            type: 'scatter3d',
            mode: 'lines+markers',
            x: x[2],
            y: y[2],
            z: z[2],
            text: text[2],
            name: 'right',
            opacity: 2,
            line: {
              width: 6,
              color: 'rgb(155, 89, 182)',
              reversescale: false
            },
            marker: {
              color: 'rgb(155, 89, 182)',
              size: 2
            }
          },
          {
            type: 'scatter3d',
            mode: 'lines+markers',
            x: x[3],
            y: y[3],
            z: z[3],
            text: text[3],
            name: 'right',
            opacity: 2,
            line: {
              width: 6,
              color: 'rgb(155, 89, 182)',
              reversescale: false
            },
            marker: {
              color: 'rgb(155, 89, 182)',
              size: 2
            }
          },
          {
            type: 'scatter3d',
            mode: 'lines+markers',
            x: x[4],
            y: y[4],
            z: z[4],
            text: text[4],
            name: 'left',
            opacity: 2,
            line: {
              width: 6,
              color: 'rgb(46, 204, 113)',
              reversescale: false
            },
            marker: {
              color: 'rgb(46, 204, 113)',
              size: 2
            }
          },
          {
            type: 'scatter3d',
            mode: 'lines+markers',
            x: x[5],
            y: y[5],
            z: z[5],
            text: text[5],
            name: 'left',
            opacity: 2,
            line: {
              width: 6,
              color: 'rgb(46, 204, 113)',
              reversescale: false
            },
            marker: {
              color: 'rgb(46, 204, 113)',
              size: 2
            }
          },
          {
            type: 'scatter3d',
            mode: 'lines+markers',
            x: x[6],
            y: y[6],
            z: z[6],
            text: text[6],
            name: 'right',
            opacity: 2,
            line: {
              width: 6,
              color: 'rgb(155, 89, 182)',
              reversescale: false
            },
            marker: {
              color: 'rgb(155, 89, 182)',
              size: 2
            }
          },
          {
            type: 'scatter3d',
            mode: 'lines+markers',
            x: x[7],
            y: y[7],
            z: z[7],
            text: text[7],
            name: 'left',
            opacity: 2,
            line: {
              width: 6,
              color: 'rgb(46, 204, 113)',
              reversescale: false
            },
            marker: {
              color: 'rgb(46, 204, 113)',
              size: 2
            }
          },
          {
            type: 'scatter3d',
            mode: 'lines+markers',
            x: x[8],
            y: y[8],
            z: z[8],
            text: text[8],
            name: 'right',
            opacity: 2,
            line: {
              width: 6,
              color: 'rgb(46, 204, 113)',
              reversescale: false
            },
            marker: {
              color: 'rgb(46, 204, 113)',
              size: 2
            }
          },
          {
            type: 'scatter3d',
            mode: 'lines+markers',
            x: x[9],
            y: y[9],
            z: z[9],
            text: text[9],
            name: 'left',
            opacity: 2,
            line: {
              width: 6,
              color: 'rgb(204, 113, 40)',
              reversescale: false
            },
            marker: {
              color: 'rgb(204, 113, 40)',
              size: 2
            }
          },
          {
            type: 'scatter3d',
            mode: 'lines+markers',
            x: x[10],
            y: y[10],
            z: z[10],
            text: text[10],
            name: 'right',
            opacity: 2,
            line: {
              width: 6,
              color: 'rgb(204, 113, 40)',
              reversescale: false
            },
            marker: {
              color: 'rgb(204, 113, 40)',
              size: 2
            }
          },
        ],
        {
          scene: {
            aspectmode: 'manual',
            aspectratio: { x: (x_max - x_min) / (z_max - z_min) * 1.3, y: (y_max - y_min) / (z_max - z_min) * 1.3, z: 1.3 },
            xaxis: {
              range: [x_min, x_max]
            },
            yaxis: {
              range: [y_min, y_max]
            },
            zaxis: {
              range: [z_min, z_max]
            },
            camera: {
              eye: {
                x: camera_x,
                y: camera_y,
                z: camera_z
              }
            },
          },
          title: plot_title,
          height: 600,
          showlegend: false,
        },
        { showSendToCloud: true }
      );
    }

  </script>

</head>

<body>
  <div id="dropzone" effectAllowed="move">Drop "xx.json" file here!
  </div>
  <div id="set3d" class="setzone">
    <table>
      <tr>
        <td>
          xRange:
        </td>
        <td>
          <input type="text" id="x_min" value="-1500" style="width:50px;" onblur="frameMove(0);">
          - <input type="text" id="x_max" value="1500" style="width:50px;" onblur="frameMove(0);">
        </td>
        <td style="padding-left:20px;">
          yRange:
        </td>
        <td>
          <input type="text" id="y_min" value="-1000" style="width:50px;" onblur="frameMove(0);">
          - <input type="text" id="y_max" value="1000" style="width:50px;" onblur="frameMove(0);">
        </td>
        <td style="padding-left:20px;">
          zRange:
        </td>
        <td>
          <input type="text" id="z_min" value="-200" style="width:50px;" onblur="frameMove(0);">
          - <input type="text" id="z_max" value="1800" style="width:50px;" onblur="frameMove(0);">
        </td>
      </tr>
      <tr>
        <td style="padding-top:5px;">
          distance:
        </td>
        <td style="padding-top:5px;">
          <input type="text" id="distance" value="2.5" style="width:50px;" onblur="frameMove(0);">
        </td>
        <td style="padding-top:5px;padding-left:20px;">
          elevationAngle:
        </td>
        <td style="padding-top:5px;">
          <input type="text" id="elev" value="18" style="width:50px;" onblur="frameMove(0);">
        </td>
        <td style="padding-top:5px;padding-left:20px;">
          azimuthAngle:
        </td>
        <td style="padding-top:5px;">
          <input type="text" id="azim" value="10" style="width:50px;" onblur="frameMove(0);">
        </td>
      </tr>
    </table>
  </div>

  <div class="setzone">
    <table>
      <tr>
        <td>
          Frame:
        </td>
        <td>
          <input type="text" id="fr" value="" style="width:50px;" onblur="frameMove(0);">
          (<input type="text" id="fr_min" value="" style="width:50px;" disabled> - <input type="text" id="fr_max"
            value="" style="width:50px;" disabled>)
        </td>
        <td style="padding-left:20px;">
          <input style="width: 50px;" class="btn" type="button" value="<30" onclick="frameMove(-30);">
          <input style="width: 50px;" class="btn" type="button" value="<5" onclick="frameMove(-5);">
          <input style="width: 50px;" class="btn" type="button" value="<1" onclick="frameMove(-1);">
          <input style="width: 50px;" class="btn" type="button" value="1>" onclick="frameMove(1);">
          <input style="width: 50px;" class="btn" type="button" value="5>" onclick="frameMove(5);">
          <input style="width: 50px;" class="btn" type="button" value="30>" onclick="frameMove(30);">
        </td>
      </tr>
      <tr>
        <td colspan="2" style="padding-top:5px;">
          <input style="width: 100px;" class="btn" type="button" value="slow play" onclick="start();">
          <input style="width: 50px;" class="btn" type="button" value="stop" onclick="stop();">
        </td>
        <td style="padding-top:5px;padding-left:20px;">
          Interval(ms):<input type="text" id="interval" value="60" style="width:50px;">
        </td>
      </tr>
    </table>
  </div>
  <div id="graph"></div>
</body>

</html>